home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / presto / prest_04.lha / src / sequent / timer.c < prev   
Encoding:
C/C++ Source or Header  |  1989-06-16  |  5.0 KB  |  235 lines

  1.  
  2. /*
  3.  * Fast timers for Dynix.
  4.  *
  5.  *
  6.  *     Last modified:        6/16/89
  7.  *    by:            sandstro
  8.  *    reason:            added the equivalent of segvh()
  9.  *                to the mmap'd kernel code
  10.  *
  11.  *     Last modified:        1/2/88
  12.  *    by:            bnb
  13.  *    reason:            add print function
  14.  *
  15.  *    Last modified:        12/21/87
  16.  *    by:            bnb
  17.  *    reason:            add these comments
  18.  *
  19.  */
  20.  
  21. #include <sys/param.h>
  22. #include <sys/file.h>
  23. #include <signal.h>
  24. #include <sys/mman.h>
  25. #include <osfcn.h>
  26. #include <nlist.h>
  27. #include <stream.h>
  28. #include "presto.h"
  29.  
  30. extern int getpagesize();
  31. extern char *shsbrk(int);
  32. extern void fatalerror();
  33. extern int mmap(caddr_t addr, int len, int prot, int share, int fd, int pos);
  34. extern char *grab_nonmalloc_hunk (int nbytes);
  35. static void check_for_hole();
  36.  
  37. static shared_t struct nlist Namelist[]    =    {
  38.     { "_time" },
  39. #define X_TIME    0
  40.     { "" }
  41. };
  42.  
  43. #define VMUNIX            "/dynix"
  44. #define KMEM            "/dev/kmem"
  45.  
  46. shared_t Spinlock timer_lock;
  47. shared_t Spinlock *t_lock = &timer_lock;
  48. private_t int t_kmemfd = -1;
  49.  
  50. shared_t struct timeval *t_tv = 0;
  51. shared_t int t_tv_all_valid = 0;    // valid in all address spaces
  52. private_t int t_tv_im_valid = 0;    // valid in this address space
  53.  
  54. shared_t int t_refcnt = 0;
  55. shared_t unsigned long timer_offt;
  56. shared_t int timer_pgsz;
  57. shared_t caddr_t timer_base;
  58.  
  59. //
  60. // Always succeed, even if we can't map
  61. //
  62.  
  63. void
  64. Timer::init()
  65. {
  66.     t_lock->lock();
  67.     
  68.     t_refcnt++;
  69.  
  70.     if (t_tv)    {
  71.         // At least one address space has already
  72.         // initialized this timer.
  73.         t_starttime = getabsolutetime();
  74.         t_lock->unlock();
  75.         return;
  76.     }
  77.     
  78.     //
  79.     // ELSE, must map kernel time var into our address space
  80.     //
  81.  
  82.     if (nlist(VMUNIX, Namelist) < 0)    {
  83.         perror("Cant get namelist");
  84.         goto out;
  85.     }
  86.     
  87.     if (Namelist[X_TIME].n_type == 0)    {
  88.         cerr << "Help... namelist is insane\n";
  89.         goto out;
  90.     }
  91.     
  92.     t_kmemfd = open(KMEM, O_RDONLY, 0);
  93.     if (t_kmemfd < 0)    {
  94.         perror("open");
  95.         cerr << "Can't open kmem for time class\n";
  96.         goto out;
  97.     }
  98.     
  99.     if (lseek(t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0)    {
  100.         perror("lseek");
  101.         cerr << "Can't lseek kmem for time class\n";
  102.         goto out;
  103.     }
  104.     
  105.     timer_pgsz = getpagesize();
  106.     timer_offt = Namelist[X_TIME].n_value & ~(timer_pgsz-1);
  107.     timer_base = grab_nonmalloc_hunk (timer_pgsz);
  108.     if (timer_base == (char *) -1) {
  109.         perror ("shbrk");
  110.         error ("Shbrk failed in Timer init");
  111.         goto out;
  112.     }
  113.     if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,t_kmemfd, timer_offt) < 0) {
  114.         perror("mmap");
  115.         error("Can't map kmem first time");
  116.         goto out;
  117.     }
  118.     
  119.     t_tv =     (struct timeval*)(timer_base + Namelist[X_TIME].n_value - timer_offt);
  120.     t_tv_im_valid = 1;
  121.     t_starttime = getabsolutetime();
  122.     t_lock->unlock();
  123.     return;
  124.     
  125. out:        
  126.     if (t_tv == 0) {
  127.         t_tv = new timeval;    // static tv for ::gettimeofday
  128.         t_tv_all_valid = 1;
  129.     }
  130.     close(t_kmemfd);
  131.     t_kmemfd = -1;            // must use system call
  132.     t_lock->unlock();
  133.     return;
  134.  
  135. }
  136.  
  137. Timer::~Timer()
  138. {
  139.  
  140.     t_lock->lock();
  141.     
  142. #ifdef SANITY
  143.     if (t_refcnt <= 0)    {
  144.         cerr << "Warning:non-positive refcnt on time destructor\n";
  145.     }
  146. #endif
  147.     
  148.     t_refcnt--;
  149.     if (t_refcnt == 0)    {
  150.         if (t_kmemfd < 0) {
  151.             t_tv_all_valid = 0;
  152.             delete t_tv;
  153.         } else    {
  154.             close(t_kmemfd);
  155.             t_tv = 0;
  156.             t_kmemfd = -1;
  157.         }
  158.         t_lock->unlock();
  159.         delete t_lock;
  160.     } else
  161.         t_lock->unlock();
  162. }
  163.  
  164. double
  165. Timer::getabsolutetime()
  166. {
  167.     check_for_hole();
  168.     return (double)t_tv->tv_sec +
  169.         ((double)(t_tv->tv_usec) * 1.0e-6);
  170. }
  171.  
  172. char*
  173. Timer::getasciitime()
  174. {
  175.     check_for_hole();
  176.     return ctime((long*)&t_tv->tv_sec);
  177. }
  178.  
  179. struct timeval* 
  180. Timer::gettimeofday()
  181. {
  182.     check_for_hole();
  183.     if (t_kmemfd < 0) {            // couldn't map
  184.         ::gettimeofday(t_tv,0);
  185.     }
  186.     return t_tv;
  187. }
  188.  
  189. void
  190. Timer::print(ostream& s)
  191. {
  192.     check_for_hole();
  193.     s << form("(Timer)this= 0x%x,", this) << 
  194.          "t_lock= " << t_lock << "\n";
  195.     s << "t_tv= " << t_tv->tv_sec << ":" << t_tv->tv_usec << "\n";
  196.     s << "t_refcnt=" << t_refcnt << ", t_starttime = " << t_starttime;
  197. }
  198.  
  199. // The following routine, check_for_hole(), allows several address spaces
  200. // to check at the last minute whether they have memory mapped /dev/kmem,
  201. // and to map it if necessary.  Sequent offers something similar for
  202. // shbrk(), called segvh().  Segvh() is discussed in section 5.2 of
  203. // ``A Parallel Programming Process Model'' by Beck and Olien,
  204. // a paper distributed at the 1988 SURF in Newport Beach, CA.
  205. // Segvh() doesn't work here, because segvh() assumes that you
  206. // want to map the file descriptor _shm_fd to your address space.
  207.  
  208. static void check_for_hole()
  209. {
  210.     // This routine assumes that Timer::init() has been called.
  211.     if (t_tv_all_valid == 0) {
  212.     // At least one routine succeeded in mmapping the kernel,
  213.     // and no processes have yet tried and failed.
  214.     if (t_tv_im_valid == 0) {
  215.         // It wasn't us that succeeded in mmapping the kernel.
  216.         t_kmemfd = open (KMEM, O_RDONLY, 0);
  217.         if (t_kmemfd < 0) {
  218.         perror ("open");
  219.         error ("open kmem for Timer");
  220.         }
  221.         if (lseek (t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
  222.         perror ("lseek");
  223.         error ("lseek kmem for Timer");
  224.         }
  225.         if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,
  226.         t_kmemfd, timer_offt) < 0) {
  227.         perror ("mmap");
  228.         error ("mmap kmem for Timer");
  229.         }
  230.     }
  231.     }
  232. }
  233.  
  234.  
  235.